package com.symaster.common.swing.element.icon;

import com.symaster.common.image.util.ImageUtil;
import com.symaster.common.swing.element.polygon.JPolygon;
import com.symaster.common.swing.util.SwingUtil;
import com.symaster.common.swing.util.ThreadPoolUtil;
import com.symaster.common.util.IOUtil;
import org.opencv.core.Mat;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.Closeable;
import java.util.concurrent.TimeUnit;

/**
 * @author yinmiao
 * @version 2022-11-02 14:57
 */
public class RotateIcon extends JComponent implements Closeable {

    private BufferedImage cacheImage;
    private Mat mat;
    private Boolean start;
    private double angleOffset;
    private long timeSleep;
    private int marge;
    private final JPolygon jPolygon;

    public static final int DIRECTION_CLOCKWISE = 1;
    public static final int DIRECTION_COUNTERCLOCKWISE = -1;

    public RotateIcon(JPolygon jPolygon) {
        // mat = ImageUtil.loadMat("D:\\startEdit\\projects\\common-zhongjia\\src\\main\\resources\\icon\\loading.png");
        mat = createImage(jPolygon);
        this.angleOffset = 30;
        this.jPolygon = jPolygon;
        this.timeSleep = 100;
        this.marge = 0;
    }

    public RotateIcon(JPolygon jPolygon, double angleOffset, long timeSleep) {
        // mat = ImageUtil.loadMat("D:\\startEdit\\projects\\common-zhongjia\\src\\main\\resources\\icon\\loading.png");
        mat = createImage(jPolygon);
        this.jPolygon = jPolygon;
        this.angleOffset = angleOffset;
        this.timeSleep = timeSleep;
        this.marge = 0;
    }

    public void setMarge(int marge) {
        this.marge = marge;
        mat = createImage(jPolygon);
    }

    private Mat createImage(JPolygon jPolygon) {

        double max = Math.max(jPolygon.getWidth(), jPolygon.getHeight());
        int ceil = (int) Math.ceil(max) + marge * 2;
        BufferedImage bufferedImage = new BufferedImage(ceil, ceil, BufferedImage.TYPE_4BYTE_ABGR);

        Graphics graphics = bufferedImage.getGraphics();
        SwingUtil.antialiasingOn((Graphics2D) graphics);

        jPolygon.move(0, 0);
        jPolygon.translate(marge, marge);

        graphics.setColor(jPolygon.getPolygonColor());
        graphics.fillPolygon(jPolygon.toAwtPolygon());

        for (JPolygon polygon : jPolygon) {
            graphics.setColor(polygon.getPolygonColor());
            graphics.fillPolygon(polygon.toAwtPolygon());
        }

        return ImageUtil.bufferedImageRGBA2MatBGRA(bufferedImage);
    }

    public void setAngleOffset(double angleOffset) {
        this.angleOffset = angleOffset;
    }

    public void setTimeSleep(long timeSleep) {
        this.timeSleep = timeSleep;
    }

    /**
     * 开始连续旋转
     *
     * @param direction 指定旋转方向, 1:顺时针, -1:逆时针
     */
    public void start(int direction) {
        start = true;
        ThreadPoolUtil.execute(() -> {
            try {
                int count = 0;
                while (start) {
                    rotate(direction > 0 ? count * angleOffset : -(count * angleOffset));
                    TimeUnit.MILLISECONDS.sleep(timeSleep);
                    count++;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public void rotate(double angle) {
        Mat mat = null;
        try {
            mat = ImageUtil.rotateTransform(this.mat, angle, this.mat.width() / 2.0D, this.mat.height() / 2.0D);
            cacheImage = (BufferedImage) ImageUtil.toBufferedImage(mat);
            SwingUtilities.invokeLater(this::repaint);
        } finally {
            IOUtil.close(mat);
        }
    }

    /**
     * 平滑旋转
     *
     * @param angle 角度
     * @param time  动画时间
     */
    public void rotate(double angle, long time) {
        if (time <= 1) {
            rotate(angle);
        }
        double s = 16.67; //
        ThreadPoolUtil.execute(() -> {

        });
    }

    public void stop() {
        start = false;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        if (cacheImage == null) {
            return;
        }
        SwingUtil.antialiasingOn((Graphics2D) g);
        g.drawImage(cacheImage, 0, 0, null);
    }

    @Override
    public void close() {
        start = false;
        cacheImage = null;
        IOUtil.close(mat);
    }
}
